﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using BoYuanCore.CoreCodeTemplates.DBMappingRules;
using BoYuanCore.CoreCodeTemplates.FineUICore;
using FreeSql;
using FreeSql.DatabaseModel;

namespace BoYuanCore.CoreCodeTemplates.FreeSql
{
    public class EntityTemplate:FineUIBase
    {
        public static string GetCode(TableModel tb,string parentClass= "SnowflakEntity")
        {
            var columnList = tb.Columns;
            StringBuilder sb = new StringBuilder();//PropertyName  //字段属性
            StringBuilder sb2 = new StringBuilder();//Constructor  //构造里默认值
            for (int i = 0; i < columnList.Count; i++)
            {
                if (!columnList[i].IsPrimaryKey)//雪花id，主键不需要生成
                {
                    sb.AppendLine("        ///<summary>");
                    sb.AppendLine("        ///Desc:" + columnList[i].Coment);
                    sb.AppendLine("        ///Default:" + GetProertypeDefaultValue(columnList[i]));
                    sb.AppendLine("        ///Nullable:" + columnList[i].IsNullable.ToString());
                    sb.AppendLine("        ///</summary>");
                    sb.Append(GetFreeSqlColumnInfo(columnList[i]));
                    sb.AppendLine("        public " + DataTypeMapping.Csharp.GetCsharpKeyword(columnList[i].CsType.Name) + " " + (columnList[i].DbColumnName) + " { get; set; }");
                    sb.AppendLine("");
                }

                if (!string.IsNullOrWhiteSpace(columnList[i].DefaultValue))//默认值
                {
                    sb2.AppendLine("             this."+ (columnList[i].DbColumnName) + " ="+ GetPropertyTypeConvert(columnList[i]) +";");
                }
                
            }

            string code = string.Format(@"
using System;
using FreeSql.DataAnnotations;

namespace {1}
{{
    ///<summary>
    ///{4}
    ///</summary>
    [Table(Name = ""{0}"")]
    [Serializable]
    public partial class {0} {5}
    {{
        public {0}()
        {{
{3}
        }}

{2}

    }}
}}

"
            , tb.TableName      //0
            , tb.NamespaceStr   //1
            , sb.ToString()     //2
            , sb2.ToString()    //3
            , GetTableDescription(tb)//4
            , string.IsNullOrEmpty(parentClass)?string.Empty:" : "+ parentClass //5
);

            return code;
        }

        /// <summary>
        /// 获取表备注信息
        /// </summary>
        /// <param name="table"></param>
        /// <returns></returns>
        private static string GetTableDescription(TableModel table)
        {
            if (string.IsNullOrWhiteSpace(table.TableDescription))
            {
                //如果表备注信息没有，则获取主键信息
                var primaryKeyColumn = table.Columns.First(p => p.IsPrimaryKey);
                if (primaryKeyColumn == null)//如果主键为null，返回空字符串(不做无主键异常)
                {
                    return string.Empty;
                }
                else //个人习惯，可以把表备注信息写在主键备注里
                {
                    return primaryKeyColumn.Coment;
                }
            }
            else
            {
                return table.TableDescription;
            }
        }

        private static string GetFreeSqlColumnInfo(DbColumnInfo column)
        {
            if (column.PropertyName == "string")
            {
                return "        [Column(StringLength = " + column.MaxLength + ")]" + Environment.NewLine;
            }

            // switch (column.PropertyName.ToLower())
            // {
            //     case "char"://break;
            //     case "nchar"://break;
            //     case "varchar"://break;
            //     case "nvarchar":
            //         if (column.MaxLength > 0)
            //         {
            //             return GetFreeSqlColumnLengthInfo(column);
            //         }
            //         break;
            // }

            return string.Empty;//nvarchar(max)
        }

        private static string GetFreeSqlColumnLengthInfo(DbColumnInfo column)
        {
            //        [Column(Length = 20)]
            //经测试，nvarchar 等数据库类型，如果长度是nvarchar(50)，对应的column.Length是100。这个约定可能是CodeFirst 模式需要的，这里由于是DBFirst生成实体，需要改成50长度。
            int columnLength = column.MaxLength;
            if (column.DbTypeText.Substring(0, 1) == "n")
            {
                if ((column.MaxLength & 1) == 1) //奇数
                {
                    columnLength = (column.MaxLength - 1) / 2;
                }
                else
                {
                    columnLength = column.MaxLength / 2;
                }
            }
            //更改为FreeSql方式
            return "        [Column(StringLength = " + columnLength + ")]" + Environment.NewLine;
        }

        #region SqlSugar 源码方法 默认值相关转换

        //todo 改成多数据库

        private static string GetProertypeDefaultValue(DbColumnInfo item)
        {
            var result = item.DefaultValue;
            if (result == null) return null;
            if (Regex.IsMatch(result, @"^\(\'(.+)\'\)$"))
            {
                result = Regex.Match(result, @"^\(\'(.+)\'\)$").Groups[1].Value;
            }
            if (Regex.IsMatch(result, @"^\(\((.+)\)\)$"))
            {
                result = Regex.Match(result, @"^\(\((.+)\)\)$").Groups[1].Value;
            }
            if (Regex.IsMatch(result, @"^\((.+)\)$"))
            {
                result = Regex.Match(result, @"^\((.+)\)$").Groups[1].Value;
            }
            if (result.Equals("getdate()", StringComparison.CurrentCultureIgnoreCase)) //此处修改sugar源码
            {
                result = "DateTime.Now";
            }
            result = result.Replace("\r", "\t").Replace("\n", "\t");
            string[] strs = { "''", "\"\"" };
            result = strs.Contains(result)? string.Empty : result;
            return result;
        }

        private static string GetPropertyTypeConvert(DbColumnInfo item)
        {
            var convertString = GetProertypeDefaultValue(item);
            if (convertString == "DateTime.Now" || convertString == null)
                return convertString;
            if (convertString.ObjToString() == "newid()")
            {
                return "Guid.NewGuid()";
            }
            if (item.DbTypeText.ToLower() == "bit")
                return (convertString == "1" || convertString.Equals("true", StringComparison.CurrentCultureIgnoreCase)).ToString().ToLower();
            string result = DataTypeMapping.Mssql.GetConvertString(item.DbTypeText.ToLower()) + "(\"" + convertString + "\")";
            return result;
        }

        #endregion

        public static global::FreeSql.DatabaseModel.DbColumnInfo GetFreesqlDbColumnInfo(DbColumnInfo item)
        {
            global::FreeSql.DatabaseModel.DbColumnInfo freeColumnInfo = new global::FreeSql.DatabaseModel.DbColumnInfo();
            freeColumnInfo.Table = new DbTableInfo();
            freeColumnInfo.Table.Name = item.TableName;
            freeColumnInfo.Name = item.DbColumnName;
            freeColumnInfo.CsType = item.CsType;
            freeColumnInfo.IsIdentity = item.IsIdentity;
            freeColumnInfo.IsNullable = item.IsNullable;
            freeColumnInfo.MaxLength = item.MaxLength;
            freeColumnInfo.Coment = item.Coment;
            freeColumnInfo.DefaultValue = item.DefaultValue;
            freeColumnInfo.IsPrimary = item.IsPrimaryKey;
            freeColumnInfo.DbTypeText = item.DbTypeText;
            freeColumnInfo.DbTypeTextFull = item.DbTypeTextFull;
            return freeColumnInfo;
        }

        /// <summary>
        /// 内置类型,根据.NET 类型转成 C# 类型关键字(例如System.Int32 转成 int)
        /// </summary>
        /// <param name="netName">.NET 类型(例如System.Int32)</param>
        /// <returns></returns>
        public static string GetCsharpKeyword(string netName)
        {
            bool isArray = netName.Contains("[]");//是否为数组类型
            string keyStr = "System." + netName.Replace("System.", "");//类似Int32 统一改成 System.Int32
            keyStr = keyStr.Replace("[]", "");//去掉数组声明

            Dictionary<string, string> dict = GetBaseTypeInfos();
            if (!dict.ContainsKey(keyStr))//不包含此key
            {
                //System.DateTime System.Guid 等。
                return netName.Replace("System.", "");
            }

            string csharpKeyword = GetBaseTypeInfos()[keyStr];
            return isArray ? csharpKeyword + "[]" : csharpKeyword;
        }

        /// <summary>
        /// 内置类型转换关系列表
        /// </summary>
        /// <returns></returns>
        public static Dictionary<string, string> GetBaseTypeInfos()
        {
            //.NET 类型 对应 C# 类型关键字
            //System.Int32 对应 int
            Dictionary<string, string> dic = new Dictionary<string, string>();
            //.NET 类型             C# 类型关键字
            dic["System.Boolean"] = "bool";
            dic["System.Byte"] = "byte";
            dic["System.SByte"] = "sbyte";
            dic["System.Char"] = "char";
            dic["System.Decimal"] = "decimal";
            dic["System.Double"] = "double";
            dic["System.Single"] = "float";
            dic["System.Int32"] = "int";
            dic["System.UInt32"] = "uint";
            dic["System.Int64"] = "long";
            dic["System.UInt64"] = "ulong";
            dic["System.Int16"] = "short";
            dic["System.UInt16"] = "ushort";

            //下面引用类型。上面是值类型
            dic["System.Object"] = "object";
            dic["System.String"] = "string";

            return dic;
        }
    }
}
